﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.IO;
using System.Linq;
using System.Text;
using SCResources.DataLayer.SCDbDataSetTableAdapters;
using SCResources.General;
using SCResources.Interfaces;

namespace SCResources.DataLayer
{
    internal class SeriesData 
    {
        private SCDbDataSet seriesDataSet;
        

        public SCDbDataSet SeriesDataSet
        {
            get
            {
                return seriesDataSet;
            }
        }

        public SeriesData()
        {
            seriesDataSet = new SCDbDataSet();

            Initdata();
        }

        ~SeriesData()
        {
            writeData();
        }
        
        private void Initdata()
        {
            if (File.Exists(IO_Settings.GetSettings().SerieListSavePath))
            {
                foreach (DataTable dataTable in seriesDataSet.Tables)
                {
                    dataTable.BeginLoadData();
                }
                seriesDataSet.ReadXml(IO_Settings.GetSettings().SerieListSavePath);

                foreach (DataTable dataTable in seriesDataSet.Tables)
                {
                    dataTable.EndLoadData();
                }
            }
        }

        internal void writeData()
        {
            seriesDataSet.WriteXml(IO_Settings.GetSettings().SerieListSavePath);
        }

        internal void ExportData(string filename)
        {
            seriesDataSet.WriteXml(filename);
        }

        /// <summary>
        /// Import xml file
        /// </summary>
        /// <param name="filename"></param>
        internal void ImportData(string filename)
        {
            try
            {
                seriesDataSet = new SCDbDataSet(); //clear current data
                foreach (DataTable dataTable in seriesDataSet.Tables)
                {
                    dataTable.BeginLoadData();
                }
                seriesDataSet.ReadXml(filename);

                foreach (DataTable dataTable in seriesDataSet.Tables)
                {
                    dataTable.EndLoadData();
                }
            }
            catch (Exception)
            {
                throw;
                //todo: add exception
            }
        }

        #region Serie Data

        /// <summary>
        /// Add serie to database
        /// </summary>
        /// <param name="serieWrapper">serie to add</param>
        /// <returns>Given wrapper with DbId filled in</returns>
        internal SerieWrapper Add(SerieWrapper serieWrapper)
        {
            SCDbDataSet.SeriesRow seriesRow = seriesDataSet.Series.NewSeriesRow();

            //create main serie row
            seriesRow.Title = serieWrapper.Title;
            seriesRow.ImdbId = serieWrapper.ImdbId;
            seriesRow.AutoAirInfo = serieWrapper.AutoAirInfo;
            if (serieWrapper.LocalDirectory != null) seriesRow.LocalDirectory = serieWrapper.LocalDirectory;
            if(serieWrapper.Cover != null)
            {
                Random random = new Random(1254);
                //IsPunctuation : prevent save error by not allowed chars in save path
                string filename = GeneralVars.DEFAULT_COVER_FOLDER_PATH + new string(serieWrapper.Title.ToCharArray().Where(c => !char.IsPunctuation(c)).ToArray()) + random.Next()+ ".jpg";
                if(IO_Covers.saveCover(filename, serieWrapper.Cover))
                    seriesRow.Cover = filename;
            }
            seriesDataSet.Series.AddSeriesRow(seriesRow);

            //create userInfo & airInfo row  if any
            if (serieWrapper.UserInfo != null)
            {
                SCDbDataSet.UserInfoRow userInfoRow = seriesDataSet.UserInfo.NewUserInfoRow();
                userInfoRow.Episode = serieWrapper.UserInfo.Episode;
                userInfoRow.Season = serieWrapper.UserInfo.Season;
                userInfoRow.SeriesRow = seriesRow;
                seriesDataSet.UserInfo.AddUserInfoRow(userInfoRow);
            }
            if(serieWrapper.AirInfo != null)
            {
                SCDbDataSet.AirInfoRow airInfoRow = seriesDataSet.AirInfo.NewAirInfoRow();
                airInfoRow.Episode = serieWrapper.AirInfo.Episode;
                airInfoRow.Season = serieWrapper.AirInfo.Season;
                airInfoRow.NextAirDate = serieWrapper.AirInfo.NextAirDate;
                airInfoRow.Frequency = serieWrapper.AirInfo.Frequency;
                airInfoRow.SeriesRow = seriesRow;
                seriesDataSet.AirInfo.AddAirInfoRow(airInfoRow);
            }

            serieWrapper.DbId = seriesRow.Id;

            return serieWrapper;

        }

        /// <summary>
        /// Get serie by Id, any changes on the data will be parmanent
        /// </summary>
        /// <param name="id"></param>
        /// <returns></returns>
        internal SerieWrapper Get(int id)
        {
            SCDbDataSet.SeriesRow seriesRow = seriesDataSet.Series.FindById(id);

            return ConvertSerieRow(seriesRow);
        }

        internal List<SerieWrapper> GetAutoAirdateTrue()
        {
            List<SerieWrapper> series = new List<SerieWrapper>();

            var serieRows = seriesDataSet.Series.Where(s => s.AutoAirInfo == true).Select(s => s);

            foreach (SCDbDataSet.SeriesRow serieRow in serieRows)
            {
                series.Add(ConvertSerieRow(serieRow));
            }

            return series;
        }

        internal List<SerieWrapper> GetAll()
        {
            List<SerieWrapper> all = new List<SerieWrapper>();

            foreach (SCDbDataSet.SeriesRow row in seriesDataSet.Series)
            {
                all.Add(ConvertSerieRow(row));
            }

            return all;
        }

        internal void Remove(int id)
        {
            SCDbDataSet.SeriesRow row = seriesDataSet.Series.FindById(id);
            row.Delete();
            //todo: remove old cover
        }

        internal void UpdateCover(int serieId, Image cover)
        {
            SCDbDataSet.SeriesRow row = seriesDataSet.Series.FindById(serieId);

            if(!row.IsCoverNull())
            {
                try
                {
                    IO_Covers.removeCover(row.Cover);
                    IO_Covers.saveCover(row.Cover, cover);
                }
                catch (Exception)
                {
                    //todo: exception
                    throw;
                }
            }
            else
            {
                Random random = new Random(1254);
                //IsPunctuation : prevent save error by not allowed chars in save path
                string filename = GeneralVars.DEFAULT_COVER_FOLDER_PATH + new string(row.Title.ToCharArray().Where(c => !char.IsPunctuation(c)).ToArray()) + random.Next() + ".jpg";
                IO_Covers.saveCover(filename, cover);
            }
        }

        //might not be needed => Get() => ref of the object so any changes are directly stored
        internal void Update(SerieWrapper serieWrapper, bool updateCover = false)
        {
            SCDbDataSet.SeriesRow seriesRow = seriesDataSet.Series.FindById(serieWrapper.DbId);

            //update main serie row
            seriesRow.Title = serieWrapper.Title;
            seriesRow.ImdbId = serieWrapper.ImdbId;
            seriesRow.AutoAirInfo = serieWrapper.AutoAirInfo;
            if (serieWrapper.LocalDirectory != null) seriesRow.LocalDirectory = serieWrapper.LocalDirectory;
            else
            {
                seriesRow.SetLocalDirectoryNull();
            }

            if (updateCover)
            {
                if (serieWrapper.Cover != null)
                {
                    Random random = new Random(1254);
                    //IsPunctuation : prevent save error by not allowed chars in save path
                    string filename = GeneralVars.DEFAULT_COVER_FOLDER_PATH + new string(serieWrapper.Title.ToCharArray().Where(c => !char.IsPunctuation(c)).ToArray()) + random.Next() + ".jpg";
                    IO_Covers.saveCover(filename, serieWrapper.Cover);
                    seriesRow.Cover = filename;
                    //todo: remove old cover
                }
                else
                {
                    seriesRow.SetCoverNull();
                }
            }

  //          seriesDataSet.Series.AcceptChanges();

            //update userInfo row if any
            if (serieWrapper.UserInfo != null)
            {
                SCDbDataSet.UserInfoRow userInfoRow = seriesDataSet.UserInfo.Where(u => u.SerieId == serieWrapper.DbId).SingleOrDefault(); //todo: check what happens if no userInfo existed
                userInfoRow.Episode = serieWrapper.UserInfo.Episode;
                userInfoRow.Season = serieWrapper.UserInfo.Season;
            }
            else
            {
                //seriesDataSet.UserInfo.RemoveUserInfoRow(seriesDataSet.UserInfo.Where(u => u.SerieId == serieId).Single());
                throw new Exception("Userinfo Cannot by Null");
            }

//            seriesDataSet.UserInfo.AcceptChanges();

            //update Airinfo
            if (serieWrapper.AirInfo != null)
            {
                bool needToAdd = false;
                SCDbDataSet.AirInfoRow airInfoRow =
                    seriesDataSet.AirInfo.Where(a => a.SerieId == serieWrapper.DbId).SingleOrDefault();

                if (airInfoRow == null)
                {
                    airInfoRow = seriesDataSet.AirInfo.NewAirInfoRow();
                    needToAdd = true;
                }

                airInfoRow.Episode = serieWrapper.AirInfo.Episode;
                airInfoRow.Season = serieWrapper.AirInfo.Season;
                airInfoRow.NextAirDate = serieWrapper.AirInfo.NextAirDate;
                airInfoRow.Frequency = serieWrapper.AirInfo.Frequency;

                if (needToAdd)
                {
                    airInfoRow.SeriesRow = seriesRow;
                    seriesDataSet.AirInfo.AddAirInfoRow(airInfoRow);
                }
            }
            else
            {
                seriesDataSet.AirInfo.RemoveAirInfoRow(seriesDataSet.AirInfo.Where(a => a.SerieId == serieWrapper.DbId).SingleOrDefault());
            }

            //todo: test if these changes are saved by editing the object
        }


        private SerieWrapper ConvertSerieRow(SCDbDataSet.SeriesRow seriesRow)
        {
            SerieWrapper serieWrapper = new SerieWrapper(seriesRow.Title, seriesRow.Id, seriesRow.ImdbId, seriesRow.Cover, seriesRow.LocalDirectory, seriesRow.AutoAirInfo);

            SCDbDataSet.UserInfoRow userInfoRow = seriesDataSet.UserInfo.Where(u => u.SerieId == seriesRow.Id).SingleOrDefault();
            if(userInfoRow != null)
            {
                serieWrapper.UserInfo = new SerieUserInfo(userInfoRow.Season,userInfoRow.Episode);
            }

            SCDbDataSet.AirInfoRow airInfoRow =
                    seriesDataSet.AirInfo.Where(a => a.SerieId == seriesRow.Id).SingleOrDefault();
            if (airInfoRow != null)
            {
                serieWrapper.AirInfo = new SerieAirInfo(airInfoRow.Season,airInfoRow.Episode,airInfoRow.NextAirDate,airInfoRow.Frequency);
            }

            return serieWrapper;
        }

        /// <summary>
        /// get a list of moveable series.
        /// </summary>
        /// <returns></returns>
        public List<FileMovingSerieObject> MoveableSeries()
        {
            List<FileMovingSerieObject> moveAbleSeries = new List<FileMovingSerieObject>();

            var moveableSeries = SeriesDataSet.Series.Where(s => s.LocalDirectory != null).Select(s => s);

            foreach (SCDbDataSet.SeriesRow serie in moveableSeries)
            {
                if (Directory.Exists(serie.LocalDirectory))
                {
                    moveAbleSeries.Add(new FileMovingSerieObject(serie.Title, serie.LocalDirectory));
                }
            }

            return moveAbleSeries;
        }

        #endregion

    }
}
